﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Diagnostics;

namespace Apriori
{
    class Program
    {
        static void Main(string[] args)
        {
            string inputfilename = args[0];
            int objectcount = Convert.ToInt32(args[1]);
            int transcount = Convert.ToInt32(args[2]);
            double minsupport = Convert.ToDouble(args[3]);
            double minconffidence = Convert.ToDouble(args[4]);

            Console.WriteLine("Ustawienia parametrów:");
            Console.WriteLine("liczba obiektów   = " + objectcount);
            Console.WriteLine("liczba transakcji = " + transcount);
            Console.WriteLine("       minsupport = " + minsupport);
            Console.WriteLine("   minconffidence = " + minconffidence);

            Stopwatch timer = new Stopwatch();

            timer.Start();
            Apriori(inputfilename, objectcount, transcount, minsupport, minconffidence);
            timer.Stop();

            Console.Write("\n\nCzas dzialania programu " + timer.Elapsed);
            Console.Write("\n\n");

            Console.ReadKey();
        }

        /// <summary>
        /// Generating association rules with usage of t-tree structure. 
        /// </summary>
        /// <param name="inputfile">Name of input data file.</param>
        /// <param name="objcount">Countity of different objects (called Products). We read first objcount Products from data file.</param>
        /// <param name="transcount">Countity of transactions that we read from input.</param>
        /// <param name="minsup">Minimal support above which we generate frequent itemsets.</param>
        /// <param name="minconf">Minimal confidence above which we accept association rule.</param>
        static void Apriori(string inputfile, int objcount, int transcount, double minsup, double minconf)
        {
            //Reads data from file. Generate root of t-tree.
            //Also saves all transactions into memory as List of Products that were bought in each transaction.
            TTree curttree = ReadData(inputfile, objcount, transcount);
            //As long as Prevelance of Current Product in a T-tree is different that 0 we generate all its children.
            curttree.Build(curttree.Root);
            //Generates all Frequent Itemsets above given minsup.
            curttree.GenFreqIsets(curttree.Root, minsup);
            //Prints all generated Frequent Itemsets alongside with its number to a .txt file
            curttree.PrintFreqents();
            //Creates permutations (subsets) of Frequent Itemsets (semi step beetwen creating Frequent Itemsets and generating Assotiation Rules).
            curttree.PrintPermutations();
            //Generates and prints to a file all assotiation rules above given minconf.
            curttree.GenerateRules(minconf);
        }

        static TTree ReadData(string inputfile, int obpower, int marketsize)
        {
            StreamReader sread = File.OpenText(inputfile);

            string firstline = sread.ReadLine();
            firstline = firstline.Remove(0, "Basket ID,".Length);
            string [] products_names = firstline.Split(',').ToArray();

            for (int i = 0; i < obpower; i++)
            {
                products_names[i] = products_names[i].Remove(0, 1);
            }

            int[] pcount = new int[obpower + 1];
            Array.Clear(pcount, 0, pcount.Length);


            Market M = new Market(marketsize);

            string line = "";
            int index = 0;
            while (index < marketsize && (line = sread.ReadLine()) != null)
            {
                Transaction curtransaction = new Transaction();
                string[] currline = line.Split(',').ToArray();
                curtransaction.SetName(currline[0]);

                for (int i = 1; i <= obpower; i++)
                {
                    int g = (currline[i] == " true") ? 1 : 0;
                    if (g > 0)
                    {
                        pcount[i]++;
                        curtransaction.goods.Add(products_names[i-1]);
                    }
                }

                M.AddTransaction(index, curtransaction);
                index++;
            }

            Itemset Lone = new Itemset();

            for (int i = 0; i < obpower; i++)
            {
                Product n = new Product(null, null, products_names[i], i, 1.0, pcount[i + 1], pcount[i + 1]);
                Lone.Add(n);
            }

            TTree t = new TTree(M, Lone);
            sread.Close();
            return t;
        }
    }
}
